﻿
using Anno.EngineData;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;

namespace Anno.DynamicApi
{
    /// <summary>
    /// 接口执行器
    /// </summary>
    public class ApiExecutor
    {
        /// <summary>
        /// 通用API执行方法
        /// </summary>
        /// <param name="apiKey"></param>
        /// <returns></returns>
        public IActionResult Executor(IDictionary<string, string> input)
        {
            var apiKey = "";
            if (input == null || input.TryGetValue(Const.Enum.Eng.PATH + "_Key", out apiKey) == false)
            {
                if (string.IsNullOrWhiteSpace(apiKey) && input.TryGetValue(Const.Enum.Eng.PATH, out apiKey) == false)
                {
                    Log.Log.Error($"apiKey={apiKey?.Replace("_", ".")}，接口不存在");
                    return ApiResult.Faild($"apiKey={apiKey?.Replace("_", ".")}，接口不存在");
                }
            }
            if (input.TryGetValue(Const.Enum.Eng.METHOD, out var method) && !apiKey.Contains("/" + method.ToString().Trim('/')))
            {
                apiKey += "/" + method.ToString().Trim('/');
            }
            return Executor(apiKey, input);
        }

        /// <summary>
        /// 通用API执行方法
        /// </summary>
        /// <param name="apiKey"></param>
        /// <returns></returns>
        public IActionResult Executor(string apiKey, object inputBody)
        {
            apiKey = '/' + apiKey.Trim('/');
            if (!ControllerList.DicApiInfo.TryGetValue(apiKey, out var apiInfo))
            {
                if (!ControllerList.DicApiInfo.TryGetValue(apiKey.Trim('/'), out apiInfo))
                {
                    Log.Log.Error($"apiKey={apiKey.Replace("_", ".")}，接口不存在");
                    return ApiResult.Faild($"apiKey={apiKey.Replace("_", ".")}，接口不存在");
                }
            }
            return Executor(apiInfo, inputBody);
        }
        /// <summary>
        /// 通用API执行方法
        /// </summary>
        /// <param name="apiInfo"></param>
        /// <returns></returns>
        public IActionResult Executor(ApiInfo apiInfo, object inputBody)
        {
            if (apiInfo == null)
            {
                Log.Log.Error($"接口不存在");
                return ApiResult.Faild($"接口不存在");
            }
            var apiKey = apiInfo.KeyWord;
           
            try
            {
                var input = inputBody;// new object();
                try
                {
                    if (null != inputBody && inputBody is Dictionary<string, string> dicInput)
                    {
                        if (dicInput.TryGetValue("Request.Path", out var pathstr) && !string.IsNullOrWhiteSpace(pathstr))
                        {
                            var pathParams = PathUtil.MatchPathParams(pathstr.Replace(Const.Enum.Eng.BasePath + "/", ""), apiInfo.Path);
                            pathParams.ForEach_(p => { dicInput[p.Key] = p.Value; });
                        }
                        if (dicInput.TryGetValue("body", out var bodystr) && !string.IsNullOrWhiteSpace(bodystr))
                        {
                            var bodys = bodystr.DeserializeObjectByJson<Dictionary<string, string>>();
                            if (bodys != null && bodys.Count > 0)
                                bodys.ForEach_(p => { dicInput[p.Key] = p.Value; }); //input = bodys;
                        }
                    }
                }
                catch { }
                var oldInput = input;
                //--------------------------------------------------------------------------------------------------------------------------------------------------------------------
                var comps = apiInfo.ExecutorList?.FindAll(f => f.Conditions.IsMatch(input));
                if (comps == null || comps.Count == 0)
                {
                    Log.Log.Error(apiKey + $"失败，{apiInfo.ApiName}未找到执行节点");
                    return ApiResult.Faild($"失败，{apiInfo.ApiName}未找到执行节点");
                }
                #region 单通讯点执行
                if (apiInfo.MultiExecutor == false || comps.Count == 1)
                {
                    var source = apiKey;
                    var comp = comps.Count == 1 ? comps[0] : PubFun.GetServerByHash(comps, source);
                    if (comp == null)
                    {
                        Log.Log.Error(apiKey + $"失败，{apiInfo.ApiName}未找到匹配的执行节点");
                        return ApiResult.Faild($"失败，{apiInfo.ApiName}未找到匹配的执行节点");
                    }
                    //--------------------------------------------------------------------------------------------------------------------------------------------------------------------
                    dynamic ReturnObj = comp.ApiExecutor(apiInfo, comp.ExecType == ExecutorType.RemoteApi ? oldInput : input);
                    if (ReturnObj == null)
                    {
                        Log.Log.Error(apiKey + $"调用失败，未执行成功");
                        return ApiResult.Faild("调用失败，未执行成功");
                    }
                    return ReturnObj;
                }
                #endregion
                #region 多通讯点同时执行
                else
                {
                    var returnList = new List<object>();
                    comps.ForEach(comp =>
                    {
                        if (comp == null)
                        {
                            //Log.Log.Error(apiKey + $"失败，{apiInfo.ApiName}未找到匹配的执行节点");
                            //return ApiResult.Faild($"失败，{apiInfo.ApiName}未找到匹配的执行节点");
                            return;
                        }
                        //--------------------------------------------------------------------------------------------------------------------------------------------------------------------
                        dynamic ReturnObj = comp.ApiExecutor(apiInfo,comp.ExecType == ExecutorType.RemoteApi ? oldInput : input);
                        if (ReturnObj == null || ReturnObj.Data == null)
                        {
                            Log.Log.Error(apiKey + $"{comp.ExecType},调用失败.");
                            returnList.Add(new { Executor = "" + comp.ExecType, Result = $"调用失败,{ReturnObj.Msg}" });
                            return;
                        }
                        returnList.Add(new { Executor = "" + comp.ExecType, Result = ReturnObj.Data });
                    });
                    var rets = ApiResult.Success(returnList);
                    return rets;
                }
                #endregion
            }
            catch (Exception ex)
            {
                var error = apiKey + ": " + ex.GetExceptionMessage();
                Console.WriteLine(error);
                Log.Log.Error(error);
                return ApiResult.Faild(error);
            }
        }
    }
}